home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/python
-
- import os
- import sys
- import subprocess
- import time
- import signal
- import errno
- import imp
- import grp
-
- sys.path.insert(0, '/usr/lib/ubiquity')
-
- import ubiquity.frontend
- import pwd
-
- from ubiquity import osextras
- from ubiquity.casper import get_casper
-
- background = '/usr/share/backgrounds/warty-final-ubuntu.png'
-
- class XStartupError(EnvironmentError):
- pass
-
- class MissingProgramError(EnvironmentError):
- pass
-
- class DM:
- def __init__(self, vt, display, default_username):
- self.vt = vt
- self.display = display
- self.server_started = False
-
- self.username = get_casper('USERNAME', default_username)
- self.uid, self.gid = pwd.getpwnam(self.username)[2:4]
- self.homedir = pwd.getpwnam(self.username)[5]
- self.uid = int(self.uid)
- self.gid = int(self.gid)
- self.groups = []
- for g in grp.getgrall():
- if self.username in g[3] or g[0] == self.username:
- self.groups.append(g[2])
-
- # Look for a frontend module; we won't actually use it (yet), but
- # this lets us find out which window manager etc. to launch. Be
- # careful that importing this here will cause the underlying library
- # to try to talk to the X server, which won't go well.
- frontend_names = ['mythbuntu_ui', 'gtk_ui', 'kde_ui']
- self.frontend = None
- for f in frontend_names:
- try:
- imp.find_module(f, ubiquity.frontend.__path__)
- self.frontend = f
- break
- except ImportError:
- pass
- else:
- raise AttributeError, ('No frontend available; tried %s' %
- ', '.join(frontend_names))
-
- def sigusr1_handler(self, signum, frame):
- self.server_started = True
-
- def drop_privileges(self):
- os.setgroups(self.groups)
- os.setgid(self.gid)
- os.setuid(self.uid)
-
- def server_preexec(self):
- signal.signal(signal.SIGUSR1, signal.SIG_IGN)
-
- def run(self, *program):
- null = open('/dev/null', 'w')
- if not os.path.exists('/var/log/installer'):
- os.makedirs('/var/log/installer')
- logfile = open('/var/log/installer/dm', 'w')
-
- signal.signal(signal.SIGUSR1, self.sigusr1_handler)
- signal.signal(signal.SIGTTIN, signal.SIG_IGN)
- signal.signal(signal.SIGTTOU, signal.SIG_IGN)
-
- servercommand = ['X', '-br', '-ac', '-noreset', self.vt, self.display]
- if self.frontend == 'mythbuntu_ui':
- servercommand.append('-dpi')
- servercommand.append('100')
-
- server = subprocess.Popen(servercommand, stdin=null, stdout=logfile, stderr=logfile, preexec_fn=self.server_preexec)
-
- os.environ['DISPLAY'] = self.display
- os.environ['HOME'] = self.homedir
-
- # Really we should select on a pipe or something, but it's not worth
- # the effort for now.
- timeout = 60
- while not self.server_started:
- status = server.poll()
- if type(status) is int and status != 0:
- raise XStartupError, "X server exited with return code " + str(status)
- if timeout == 0:
- raise XStartupError, "X server failed to start after 60 seconds"
- time.sleep(1)
- timeout -= 1
-
- # Session bus, apparently needed by most interfaces now
- if ('DBUS_SESSION_BUS_ADDRESS' not in os.environ and
- osextras.find_on_path('dbus-launch')):
- dbus_subp = subprocess.Popen(
- ['dbus-launch', '--exit-with-session'],
- stdin=null, stdout=subprocess.PIPE, stderr=logfile,
- preexec_fn=self.drop_privileges)
- for line in dbus_subp.stdout:
- try:
- name, value = line.rstrip('\n').split('=', 1)
- os.environ[name] = value
- except ValueError:
- pass
- dbus_subp.wait()
-
- gconfd_running = False
- if ((self.frontend == 'gtk_ui' or self.frontend == 'mythbuntu_ui') and
- osextras.find_on_path('gconftool-2')):
- subprocess.call(['gconftool-2', '--spawn'],
- stdin=null, stdout=logfile, stderr=logfile,
- preexec_fn=self.drop_privileges)
- gconfd_running = True
-
- extras = []
- if self.frontend == 'gtk_ui' or self.frontend == 'mythbuntu_ui':
- gconf_dir = ('xml:readwrite:%s' %
- os.path.expanduser('~%s/.gconf' %
- self.username))
- accessibility = 'false'
- if osextras.find_on_path('gconftool-2'):
- subprocess.call(
- ['gconftool-2', '--config-source', gconf_dir,
- '--type', 'int', '--set',
- '/apps/metacity/general/num_workspaces', '1'],
- stdin=null, stdout=logfile, stderr=logfile,
- preexec_fn=self.drop_privileges)
- subp = subprocess.Popen(
- ['gconftool-2', '--config-source', gconf_dir,
- '--get', '/desktop/gnome/interface/accessibility'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- preexec_fn=self.drop_privileges)
- accessibility = subp.communicate()[0].rstrip('\n')
- # Accessibility infrastructure
- if accessibility == 'true':
- if os.path.exists('/usr/lib/at-spi/at-spi-registryd'):
- extras.append(subprocess.Popen(['/usr/lib/at-spi/at-spi-registryd'],
- stdin=null, stdout=logfile, stderr=logfile))
- os.environ['GTK_MODULES'] = 'gail:atk-bridge'
-
- maybe_drop_privileges = {}
- if accessibility != 'true':
- maybe_drop_privileges['preexec_fn'] = self.drop_privileges
-
- # Don't show the background image in v1 accessibility profile. It
- # is not shown in the GNOME desktop after all.
- fp = open('/proc/cmdline', 'r')
- if os.access(background, os.R_OK) and not 'access=v1' in fp.readline():
- import gtk
- pixbuf = gtk.gdk.pixbuf_new_from_file(background)
- root = gtk.gdk.get_default_root_window()
- (root_width, root_height) = root.get_size()
- scaled = pixbuf.scale_simple(root_width, root_height, gtk.gdk.INTERP_BILINEAR)
- (pixmap, mask) = scaled.render_pixmap_and_mask(0)
- root.set_back_pixmap(pixmap, False)
- root.clear()
- gtk.gdk.flush()
- fp.close()
-
- if self.frontend in ('gtk_ui', 'mythbuntu_ui'):
- if gconfd_running and osextras.find_on_path('metacity'):
- wm = subprocess.Popen(['metacity', '--sm-disable'],
- stdin=null, stdout=logfile, stderr=logfile,
- **maybe_drop_privileges)
- elif osextras.find_on_path('xfwm4'):
- wm = subprocess.Popen('xfwm4',
- stdin=null, stdout=logfile, stderr=logfile,
- **maybe_drop_privileges)
- elif osextras.find_on_path('matchbox-window-manager'):
- wm = subprocess.Popen('matchbox-window-manager',
- stdin=null, stdout=logfile, stderr=logfile,
- **maybe_drop_privileges)
- else:
- raise MissingProgramError, \
- "No window manager found (tried metacity, xfwm4, matchbox-window-manager)"
-
- if os.path.exists('/usr/lib/gnome-settings-daemon/gnome-settings-daemon'):
- extras.append(subprocess.Popen(['/usr/lib/gnome-settings-daemon/gnome-settings-daemon'],
- stdin=null, stdout=logfile, stderr=logfile, **maybe_drop_privileges))
-
- # Accessibility tools
- if accessibility == 'true':
- fp = open('/proc/cmdline', 'r')
- if 'access=m2' in fp.readline():
- if osextras.find_on_path('onboard'):
- extras.append(subprocess.Popen(['onboard'],
- stdin=null, stdout=logfile, stderr=logfile))
- else:
- if osextras.find_on_path('orca'):
- time.sleep(15)
- extras.append(subprocess.Popen(['orca', '-sudo', self.username, '-n'],
- stdin=null, stdout=logfile, stderr=logfile))
- fp.close()
- elif self.frontend == 'kde_ui':
- extras.append(subprocess.Popen(['kwriteconfig', '--file', 'kwinrc', '--group', 'Compositing', '--key', 'Enabled', 'false'], stdin=null, stdout=logfile, stderr=logfile, preexec_fn=self.drop_privileges))
- wm = subprocess.Popen('kwin', stdin=null, stdout=logfile,
- stderr=logfile, preexec_fn=self.drop_privileges)
-
- greeter = subprocess.Popen(program, stdin=null, stdout=logfile, stderr=logfile)
- ret = greeter.wait()
-
- def kill_if_exists(pid, signum):
- try:
- os.kill(pid, signum)
- except OSError, e:
- if e.errno != errno.ESRCH:
- raise
-
- def sigalrm_handler(signum, frame):
- kill_if_exists(wm.pid, signal.SIGKILL)
- for extra in extras:
- kill_if_exists(extra.pid, signal.SIGKILL)
-
- kill_if_exists(wm.pid, signal.SIGTERM)
- for extra in extras:
- kill_if_exists(extra.pid, signal.SIGTERM)
- if gconfd_running:
- subprocess.call(['gconftool-2', '--shutdown'],
- stdin=null, stdout=logfile, stderr=logfile,
- preexec_fn=self.drop_privileges)
- signal.signal(signal.SIGALRM, sigalrm_handler)
- signal.alarm(1) # low patience with WMs failing to exit on demand
- processes = set(extras)
- processes.add(wm)
- while processes:
- done = set()
- for process in processes:
- try:
- process.wait()
- done.add(process)
- except OSError, e:
- if e.errno == errno.EINTR:
- continue
- raise
- processes -= done
- signal.alarm(0)
- kill_if_exists(server.pid, signal.SIGTERM)
- server.wait()
-
- if ret is not None and ret >= 0:
- return ret
- else:
- return 1
-
- if len(sys.argv) < 4:
- sys.stderr.write('Usage: %s <vt[1-N]> <:[0-N]> <username> <program> [<arguments>]\n' % sys.argv[0])
- sys.exit(1)
-
- vt, display, username = sys.argv[1:4]
- try:
- dm = DM(vt, display, username)
- except XStartupError:
- sys.exit(1)
- proc = None
- if dm.frontend == 'gtk_ui' or dm.frontend == 'mythbuntu_ui':
- proc = ['/etc/init.d/gdm', 'start']
- elif dm.frontend == 'kde_ui':
- proc = ['/etc/init.d/kdm', 'start']
- ret = dm.run(*sys.argv[4:])
- if proc:
- subprocess.Popen(proc)
- sys.exit(ret)
-